home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 October: Mac OS SDK / Dev.CD Oct 00 SDK1.toast / Development Kits / Mac OS / Display Manager SDK / Sample Code / Display Changed CWPro4 / displays.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-07-21  |  13.5 KB  |  501 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. #
  3. #        displays.c
  4. #
  5. #        This segment handles the Display Manager notification and
  6. #        repositions application windows in response.
  7. #
  8. #        Author(s):     Michael Marinkovich
  9. #                    Eric3 anderson
  10. #                    marink@apple.com
  11. #                    eric3@apple.com
  12. #
  13. #        Modification History: 
  14. #
  15. #            7/21/99        ewa        Updated to CW Pro 4. Added sample for use of 
  16. #                                DMRegisterExtendedNotifyProc to match the use
  17. #                                of the AppleEvent notification mechanism.
  18. #            1/19/99        ewa     No longer use nil as the "actualSize" param for
  19. #                                AEGetKeyPtr. The AE Mgr uses actualSize and
  20. #                                writes to its location (zero if actualSize==nil).                     
  21. #            1/19/99        ewa     update to CWPro3 and universal interfaces                     
  22. #            10/05/96    MWM        Removed the fixed window title bar height and
  23. #                                replaced it with a func that calculates the
  24. #                                proper height.
  25. #            10/12/95    MWM     Initial coding                     
  26. #
  27. #
  28. #        Copyright © 1992-1999 Apple Computer, Inc., All Rights Reserved
  29. #
  30. #
  31. #        You may incorporate this sample code into your applications without
  32. #        restriction, though the sample code has been provided "AS IS" and the
  33. #        responsibility for its operation is 100% yours.  However, what you are
  34. #        not permitted to do is to redistribute the source as "DSC Sample Code"
  35. #        after having made changes. If you're going to re-distribute the source,
  36. #        we require that you make it clear in the source that the code was
  37. #        descended from Apple Sample Code, but that you've made changes.
  38. #
  39. *************************************************************************************/
  40.  
  41. #include <Events.h>
  42. #include <ToolUtils.h>
  43. #include <Gestalt.h>
  44. #include <OSUtils.h>
  45. #include <Displays.h>
  46.  
  47.  
  48. #include "App.h"
  49. #include "Proto.h"
  50.  
  51. // Set to 1 to install DM extended notifications
  52. // Set to 0 to install AppleEvent notifications
  53. #define USE_DMEXTENDED_NOTIFY                    0
  54.  
  55.  
  56. //----------------------------------------------------------------------
  57. //
  58. // Decide at compile time to use AppleEvents or DM extended notifications
  59. //                      
  60. //----------------------------------------------------------------------
  61.  
  62. OSErr InstallDMNotification(void)
  63. {
  64.     OSErr            err = noErr;
  65.     
  66. #if USE_DMEXTENDED_NOTIFY
  67.         err = InstallExtendedDMNotification();     // install DM extended Display Notification
  68. #else
  69.         err = InstallAEDMNotification();         // install AppleEvent Display Notification
  70. #endif
  71.  
  72.     return err;
  73.  
  74. }
  75.  
  76. //----------------------------------------------------------------------
  77. //
  78. //    InstallAEDMNotification - tell DM that we want to be notified by AE.
  79. //                      
  80. //----------------------------------------------------------------------
  81.  
  82. OSErr InstallAEDMNotification(void)
  83. {
  84.     OSErr            err = noErr;
  85.     
  86.     err = AEInstallEventHandler(kCoreEventClass, kAESystemConfigNotice,
  87.                                 NewAEEventHandlerProc(WorldChangedAppleEventProc),
  88.                                 0L, false);
  89.     return err;
  90.  
  91. }
  92.  
  93.  
  94. //----------------------------------------------------------------------
  95. //
  96. //    WorldChangedAppleEventProc - Display Manager calls this proc when a depth or  
  97. //                                   mode change is made. Your application should
  98. //                                   handle window repositioning here. 
  99. //                      
  100. //----------------------------------------------------------------------
  101.  
  102. pascal OSErr WorldChangedAppleEventProc(AppleEvent event, AppleEvent reply, long refCon)
  103. {
  104.     OSErr            err = noErr;
  105.  
  106.     err = HandleNotification(&event);
  107.     
  108.     return noErr;
  109.     
  110. }
  111.  
  112. //----------------------------------------------------------------------
  113. //
  114. //    InstallExtendedDMNotification - tell DM that we want to be have an
  115. //                                    extended notification. Note that we
  116. //                                    leak the UPP. We should remember it
  117. //                                    and toss it when we no longer need
  118. //                                    it.
  119. //                      
  120. //----------------------------------------------------------------------
  121.  
  122. OSErr InstallExtendedDMNotification(void)
  123. {
  124.     OSErr                            err = noErr;
  125.     DMExtendedNotificationUPP        panelNotificationUPP = nil;
  126.     ProcessSerialNumber                currentPSN;
  127.  
  128.     (void)GetCurrentProcess(¤tPSN);
  129.     panelNotificationUPP = NewDMExtendedNotificationProc(WorldChangedExtendedProc);
  130.     err = DMRegisterExtendedNotifyProc(    panelNotificationUPP,        // the proc to notify
  131.                                         (void *) nil,                // user data (we have none)
  132.                                         (unsigned short) nil,        // currently unused - set to zero
  133.                                         ¤tPSN);                // our app process serial number
  134.  
  135.     return err;
  136.  
  137. }
  138.  
  139. //----------------------------------------------------------------------
  140. //
  141. //    WorldChangedExtendedProc -    Display Manager calls this proc when a depth or  
  142. //                                 mode change is made. Your application should
  143. //                                 handle window repositioning here. 
  144. //                      
  145. //----------------------------------------------------------------------
  146.  
  147. pascal OSErr WorldChangedExtendedProc(void* userData,short theMessage,void* notifyData)
  148. {
  149.     OSErr            err = noErr;
  150.                                                 // Take a look at Displays.h for the
  151.                                                 // full list of event types.
  152.     if (theMessage == kDMNotifyEvent)            // post-notification event
  153.     {
  154.         err = HandleNotification((AppleEvent *)notifyData);
  155.     }
  156.     return noErr;
  157.     
  158. }
  159.  
  160. //----------------------------------------------------------------------
  161. //
  162. //    HandleNotification - handle the AppleEvent returned by the 
  163. //                           AppleEvent procedure.
  164. //                      
  165. //----------------------------------------------------------------------
  166.  
  167. OSErr HandleNotification(AppleEvent *event)
  168. {
  169.     OSErr                    err = noErr;
  170.     GrafPtr                    oldPort;
  171.     AEDescList                displayList;
  172.     AEDescList                aDisplay;
  173.     AERecord                oldConfig,newConfig;
  174.     AEKeyword                tempWord;
  175.     DisplayIDType            displayID;
  176.     unsigned long            returnType;
  177.     long                    count;
  178.     Rect                    oldRect, newRect;
  179.     Size                    actualSizeUnused;    
  180.     
  181.     GetPort(&oldPort);
  182.  
  183.     // Get a list of the displays from the Display Notice AppleEvent.
  184.     err = AEGetParamDesc(event,kAEDisplayNotice,typeWildCard,&displayList);
  185.     // How many items in the list
  186.     err = AECountItems(&displayList,&count);
  187.     
  188.     while (count > 0)          // Loop through the list.
  189.     {
  190.         err = AEGetNthDesc(&displayList, count, typeWildCard, &tempWord, 
  191.                                     &aDisplay);
  192.         
  193.         // Get the Old Rect.            
  194.         err = AEGetNthDesc(&aDisplay, 1, typeWildCard, &tempWord, 
  195.                            &oldConfig);
  196.         err = AEGetKeyPtr(&oldConfig, keyDeviceRect, typeWildCard, 
  197.                           &returnType, &oldRect, 8, &actualSizeUnused);
  198.         
  199.         // Get the DisplayID so we can get the GDevice later.                
  200.         err = AEGetKeyPtr(&oldConfig, keyDisplayID, typeWildCard, 
  201.                           &returnType, &displayID, 8, &actualSizeUnused);
  202.  
  203.         // Get the New Rect.                
  204.         err = AEGetNthDesc(&aDisplay, 2, typeWildCard, &tempWord, 
  205.                            &newConfig);
  206.         err = AEGetKeyPtr(&newConfig, keyDeviceRect, typeWildCard, 
  207.                           &returnType, &newRect, 8, &actualSizeUnused);
  208.         
  209.         // If the New and Old rects are not the same then we can assume
  210.         // the GDevice has changed and we need to rearrange the windows.
  211.         if (err == noErr && !EqualRect(&newRect, &oldRect))
  212.             HandleDeviceChange(displayID, &newRect);
  213.  
  214.         count--;
  215.         err = AEDisposeDesc(&aDisplay);
  216.         err = AEDisposeDesc(&oldConfig);
  217.         err = AEDisposeDesc(&newConfig);
  218.  
  219.     }
  220.     
  221.     err = AEDisposeDesc(&displayList);
  222.     SetPort(oldPort);
  223.     
  224.     return err;
  225.     
  226. }
  227.  
  228.  
  229. //----------------------------------------------------------------------
  230. //
  231. //    HandleDeviceChange - called when the oldconfig is different from 
  232. //                         newconfig. Will check all windows on effected 
  233. //                           device and move if needed.
  234. //----------------------------------------------------------------------
  235.  
  236. OSErr HandleDeviceChange(DisplayIDType displayID, Rect *newRect)
  237. {
  238.     OSErr            err;
  239.     GDHandle        gd;
  240.     GDHandle        onGD;
  241.     WindowRef        window;
  242.     
  243.     // Get the GDevice from the DisplayID.
  244.     err = DMGetGDeviceByDisplayID((DisplayIDType) displayID, &gd, false);
  245.  
  246.     if (err == noErr && gd != nil) 
  247.     {
  248.         window = LMGetWindowList();
  249.         
  250.         while (nil != window) 
  251.         {
  252.             SetPort(window); 
  253.             // which device holds the greatest portion of the window
  254.             onGD = GetGreatestDevice(window);
  255.             
  256.             // If the window is not 50% or greater on
  257.             // the desired device then pass it up.
  258.             if (onGD == gd) 
  259.             { 
  260.                 if (OutOfBoundsRect(window->portRect, *newRect)) 
  261.                 {
  262.                     MoveInbounds(window, gd, *newRect); 
  263.                     if (OutOfBoundsRect(window->portRect, *newRect)) 
  264.                     {
  265.                         ResizeInbounds(window, gd, *newRect);
  266.                         
  267.                         // If it is one of our document windows then we need
  268.                         // to reset the std state and the scroll bars.
  269.                         if (GetIsAppWindow(window))
  270.                             AdjustScrollbars(window, true);
  271.                     }        
  272.                 }
  273.                 ResetStdState(window);
  274.  
  275.             }    
  276.             window = (WindowRef)(((WindowPeek)window)->nextWindow);
  277.         }
  278.     }
  279.     
  280.     return err;
  281.     
  282. }
  283.  
  284.     
  285. //----------------------------------------------------------------------
  286. //
  287. //    OutOfBoundsRect -  check to see if the window is out of the device
  288. //                       rect.
  289. //                      
  290. //----------------------------------------------------------------------
  291.  
  292. Boolean OutOfBoundsRect(Rect windRect, Rect screenRect)
  293. {
  294.     Boolean        out = false;
  295.     
  296.  
  297.     GlobalToLocal(&TopLeft(screenRect));
  298.     GlobalToLocal(&BotRight(screenRect));
  299.         
  300.     if ((windRect.right > screenRect.right) || (windRect.bottom > screenRect.bottom))
  301.         out = true;
  302.  
  303.     if ((windRect.left < screenRect.left) || (windRect.top < screenRect.top))
  304.         out = true;
  305.         
  306.     return out;
  307.     
  308. }
  309.     
  310.     
  311. //----------------------------------------------------------------------
  312. //
  313. //    MoveInbounds -  Move window on to desired device
  314. //                        
  315. //                      
  316. //----------------------------------------------------------------------
  317.  
  318. void MoveInbounds(WindowRef window, GDHandle gd, Rect screenRect)
  319. {
  320.     Rect        bounds;
  321.     short        hGlobal;
  322.     short        vGlobal;
  323.     
  324.     bounds = window->portRect;
  325.     
  326.     LocalToGlobal(&TopLeft(bounds));
  327.     LocalToGlobal(&BotRight(bounds));
  328.     
  329.     hGlobal = bounds.left;
  330.     vGlobal = bounds.top;
  331.     
  332.     // we want to make the left top a priority so adjust it first
  333.     // as to override the bottom, right movements. This is so we
  334.     // can resize the window later. No need to adjust the top 
  335.     // because the top coordinates don't change.
  336.     
  337.     if (((bounds.right - bounds.left) > (screenRect.right - screenRect.left)) ||
  338.         ((bounds.bottom - bounds.top) > (screenRect.bottom - screenRect.top))) 
  339.     {
  340.         
  341.         // adjust left
  342.         if (bounds.left < screenRect.left)
  343.             hGlobal = screenRect.left + 4;
  344.         
  345.         vGlobal = screenRect.top;
  346.         if (gd == GetMainDevice())
  347.             vGlobal += (GetMBarHeight() + GetWTitleHeight(window));
  348.  
  349.     }    
  350.     else 
  351.     {
  352.         // adjust left
  353.         if (bounds.left < screenRect.left)
  354.             hGlobal = screenRect.left + 4;
  355.  
  356.         if ((bounds.top - 100 < screenRect.top) && (gd == GetMainDevice()))
  357.             vGlobal = screenRect.top + (GetMBarHeight() + GetWTitleHeight(window));
  358.  
  359.         // adjust right
  360.         if (bounds.right > screenRect.right)
  361.             hGlobal = (screenRect.right - (bounds.right - bounds.left)) - 4;
  362.         
  363.         // adjust bottom
  364.         if (bounds.bottom > screenRect.bottom)
  365.             vGlobal = (screenRect.bottom - (bounds.bottom - bounds.top)) - 4;
  366.     }
  367.     
  368.     MoveWindow(window, hGlobal, vGlobal,false);
  369.         
  370. }
  371.     
  372.  
  373. //----------------------------------------------------------------------
  374. //
  375. //    ResizeInbounds -  resize the window to fit in the graphics device
  376. //                        
  377. //                      
  378. //----------------------------------------------------------------------
  379.  
  380. void ResizeInbounds(WindowRef window, GDHandle gd, Rect screenRect)
  381. {
  382.     Rect        windRect;
  383.     short        h;
  384.     short        v;
  385.  
  386.     windRect = window->portRect;
  387.     
  388.     // make the window bounds the size of the gdRect
  389.     // less the fudge factor.
  390.     h = windRect.right - windRect.left;
  391.     v = windRect.bottom - windRect.top;
  392.  
  393.     if (h > screenRect.right - screenRect.left)
  394.         h = (screenRect.right - screenRect.left) - 8;
  395.     
  396.     if (v > screenRect.bottom - screenRect.top) 
  397.     {
  398.         v = (screenRect.bottom - screenRect.top) - 8;
  399.         
  400.         // If we are on the main device then subtract the mBar
  401.         // height. Also subtract the height of the title
  402.         // bar on the window. 
  403.         
  404.         if (gd == GetMainDevice())
  405.             v -= (LMGetMBarHeight() + GetWTitleHeight(window));
  406.     }        
  407.  
  408.         
  409.     SizeWindow(window, h, v, true);
  410.  
  411. }
  412.     
  413.  
  414. //----------------------------------------------------------------------
  415. //
  416. //    GetGreatestDevice - find thw device that holds the greatest area 
  417. //                        of the window.
  418. //                      
  419. //----------------------------------------------------------------------
  420.  
  421. GDHandle GetGreatestDevice(WindowRef window)
  422. {
  423.     GDHandle    gd;
  424.     GDHandle    savedGD;
  425.     Rect        gdRect;
  426.     Rect        foundRect;
  427.     long        size;
  428.     long        greatest = nil;
  429.  
  430.     gd = DMGetFirstScreenDevice(dmOnlyActiveDisplays);
  431.     savedGD = gd;
  432.     
  433.     // Loop through the device list
  434.     while (gd != nil) 
  435.     {    
  436.         gdRect = (**gd).gdRect;
  437.         
  438.         GlobalToLocal(&topLeft(gdRect));
  439.         GlobalToLocal(&botRight(gdRect));
  440.         
  441.         if (SectRect(&window->portRect, &gdRect, &foundRect)) 
  442.         {
  443.             size = ((long)(foundRect.right - foundRect.left) * 
  444.                    (long)(foundRect.bottom - foundRect.top));
  445.             
  446.             if (size > greatest) 
  447.             {
  448.                 greatest = size;
  449.                 savedGD = gd;        // save the greatest device
  450.             }    
  451.         }
  452.         gd = DMGetNextScreenDevice(gd, dmOnlyActiveDisplays);
  453.     }
  454.     
  455.     return savedGD;
  456.     
  457. }
  458.  
  459.  
  460. //----------------------------------------------------------------------
  461. //
  462. //    ResetStdState - since we are now on a different size screen we need
  463. //                    to change the stdState window size so our zooming
  464. //                    will work properly.  
  465. //----------------------------------------------------------------------
  466.  
  467. void ResetStdState(WindowRef window)
  468. {
  469.     Rect        screenRect;
  470.     
  471.     screenRect = window->portRect;
  472.  
  473.     LocalToGlobal(&TopLeft(screenRect));
  474.     LocalToGlobal(&BotRight(screenRect));
  475.     
  476.     SetWindowStandardState(window, &screenRect);
  477.     
  478. }
  479.     
  480.     
  481. //----------------------------------------------------------------------
  482. //
  483. //    GetWTitleHeight - return the height of the titlebar for a given
  484. //                      window. If the window is nil a zero height will
  485. //                        be returned.
  486. //----------------------------------------------------------------------
  487.     
  488. short GetWTitleHeight(WindowRef window)
  489. {
  490.     short            tHeight = 0;
  491.     
  492.     if (nil != window)                
  493.         tHeight = (**((WindowPeek)window)->contRgn).rgnBBox.top - 
  494.                      (**((WindowPeek)window)->strucRgn).rgnBBox.top;
  495.     
  496.     return tHeight;
  497.  
  498. }
  499.     
  500.  
  501.